package com.hitqz.robot.biz.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hitqz.robot.api.business.dto.PatrolResultExcelDto;
import com.hitqz.robot.api.business.dto.cvd.CvdSafeExcelDto;
import com.hitqz.robot.api.business.entity.PatrolResultEntity;
import com.hitqz.robot.api.business.entity.RobotWarningRecordEntity;
import com.hitqz.robot.api.business.entity.TicketsEntity;
import com.hitqz.robot.api.business.params.QueryPatrolDetailNewParams;
import com.hitqz.robot.api.business.params.QueryPatrolSummaryNewParams;
import com.hitqz.robot.api.business.params.QueryPatrolSummaryParams;
import com.hitqz.robot.api.business.util.ExcelUtil;
import com.hitqz.robot.api.business.vo.*;
import com.hitqz.robot.biz.service.PatrolResultService;
import com.hitqz.robot.biz.service.RobotWarningRecordService;
import com.hitqz.robot.biz.service.TicketsService;
import com.hitqz.robot.common.core.util.R;
import com.hitqz.robot.common.core.util.RedisUtils;
import com.hitqz.robot.common.file.core.FileProperties;
import com.hitqz.robot.common.security.util.SecurityUtils;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletResponse;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.repository.query.Param;
import org.springframework.web.bind.annotation.*;

import java.io.File;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.time.ZoneId;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;

/**
 * @author wengyx
 * @date 2024/8/7
 */

@RestController
@AllArgsConstructor
@RequestMapping("/patrolResult")
@Tag(name = "巡检结果管理")
@Slf4j
public class PatrolResultController {

    final private PatrolResultService patrolResultService;

    final private TicketsService ticketsService;

    private final FileProperties fileProperties;

    private final ExecutorService customThreadPool;

    private final RobotWarningRecordService robotWarningRecordService;

    @PostMapping("/summary/page")
    @Operation(summary = "分页查询巡检总览")
    public R<Page<PatrolResultSummaryVo>> summaryPage(@RequestBody QueryPatrolSummaryParams query) {
        Page<PatrolResultSummaryVo> page = new Page<>(query.getCurrent(), query.getSize());
        Page<PatrolResultSummaryVo> voPage = patrolResultService.summaryPage(page, query);
        return R.ok(voPage);
    }


    @GetMapping("/graph/tree")
    @Operation(summary = "属性结构")
    public R tree(@Param("searchName") String searchName) {

        List<Tree<String>> trees = patrolResultService.buildDeviceTree(searchName);
        return R.ok(trees);
    }

    @GetMapping("/graph/deviceItems")
    @Operation(summary = "点位")
    public R deviceItems(@Param("robotSn") String robotSn, @Param("devPath") String devPath) {

        //List<String> deviceItems = patrolResultService.getDeviceItems("ZQ1", "表计1");
        List<String> deviceItems = patrolResultService.getDeviceItems(robotSn, devPath);
        System.out.println(deviceItems);

        return R.ok(deviceItems);
    }

    @GetMapping("/graph/list")
    @Operation(summary = "检测项")
    public R<PatrolGraphResultVo> patrolResult(@Param("robotSn") String robotSn, @Param("devPath") String devPath,
                                               @Param("itemName") String itemName,
                                               @Param("beginTime") String beginTime, @Param("endTime") String endTime) {
        Date dateBegin = DateUtil.parse(beginTime);
        Date dateEnd = DateUtil.parse(endTime);
        List<PatrolResultEntity> itemValues = patrolResultService.getItemValues(robotSn, devPath, itemName, dateBegin, dateEnd);
        PatrolGraphResultVo patrolGraphResultVo = mapToGraphResult(itemValues);

        return R.ok(patrolGraphResultVo);
    }

    public record OneKeyAuditParam(@Schema(description = "内操") String auditor,
                                   @Schema(description = "外操") String operator,
                                   @Schema(description = "审核意见") String auditRemark,
                                   @Schema(description = "原因") String cause) {
    }

    @PostMapping("/oneKeyAudit/{ticketsId}")
    @Operation(summary = "一键审核")
    public R oneKeyAudit(@PathVariable("ticketsId") Integer ticketsId, @RequestBody OneKeyAuditParam param) {
//        TicketsEntity tickets = ticketsService.getById(ticketsId);
        List<PatrolResultEntity> list = patrolResultService.list(Wrappers.<PatrolResultEntity>lambdaQuery().eq(PatrolResultEntity::getAuditStatus, 0).eq(PatrolResultEntity::getTicketsId, ticketsId));
//        List<RobotWarningRecordEntity> warningList = new ArrayList<>();
        list.forEach(patrolResult -> {
            patrolResult.setAuditStatus(3);
            patrolResult.setAuditor(StrUtil.isBlank(param.auditor) ? SecurityUtils.getUser().getUsername() : param.auditor);
            patrolResult.setOperator(StrUtil.isBlank(param.operator) ? SecurityUtils.getUser().getUsername() : param.operator);
            patrolResult.setCause(StrUtil.isBlank(param.cause) ? null : param.cause);
            patrolResult.setAuditRemark(StrUtil.isBlank(param.auditRemark) ? "一键审核" : "一键审核\n" + param.auditRemark);
            patrolResult.setAuditTime(new Date());
//           if (patrolResult.getStatus()==2){
//               RobotWarningRecordEntity warning = new RobotWarningRecordEntity();
//               //warning.setId(null);
//               warning.setType("2");
//               warning.setServiceId(Optional.ofNullable(tickets).map(TicketsEntity::getAllotRobotSn).orElse(""));
//               warning.setTitle(Optional.ofNullable(tickets).map(TicketsEntity::getAllotRobotName).orElse("")+":检测告警");
//               warning.setContent(patrolResult.getItemName()+",值:"+patrolResult.getShowValue()+",异常(标准:"+patrolResult.getNormalValue()+")");
//               warning.setTime(patrolResult.getCheckTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime());
//               warning.setLevel(0);
//               warning.setFlag("0");
//               warning.setFiles(patrolResult.getVisionMediaUrl());
//               warning.setPatrolResultId(patrolResult.getId());
//               warningList.add(warning);
//           }
        });
        patrolResultService.updateBatchById(list);
//        if (!warningList.isEmpty()){
//            robotWarningRecordService.saveBatch(warningList);
//        }
        return R.ok();
    }

    @PostMapping("/summary/{ticketsId}")
    @Operation(summary = "分页查询巡检详情")
    public R<Page<PatrolResultVo>> summaryPage(@PathVariable("ticketsId") Integer ticketsId, @RequestBody QueryPatrolSummaryParams query) {
        TicketsEntity tickets = ticketsService.getOne(Wrappers.<TicketsEntity>lambdaQuery().eq(TicketsEntity::getId, ticketsId).last("limit 1"));
        int ticketsStatus = Optional.ofNullable(tickets).map(TicketsEntity::getStatus).orElse(0);
        String robotSn = Optional.ofNullable(tickets).map(TicketsEntity::getAllotRobotSn).orElse("");
        Page<PatrolResultEntity> page = new Page<>(query.getCurrent(), query.getSize());
        Page<PatrolResultEntity> data = patrolResultService.page(page, Wrappers.<PatrolResultEntity>lambdaQuery()
                .eq(query.getId() != null, PatrolResultEntity::getId, query.getId())
                .eq(PatrolResultEntity::getTicketsId, ticketsId)
                .eq(query.getStatus() != null, PatrolResultEntity::getStatus, query.getStatus())
                .eq(StringUtils.isNotBlank(query.getStoveExecNo()), PatrolResultEntity::getStoveExecNo, query.getStoveExecNo())
                .orderByAsc(ticketsStatus == 0 || ticketsStatus == 1 || ticketsStatus == 2, PatrolResultEntity::getId)
                // 完成后的排序
                .orderByAsc(!robotSn.contains("HITRAIL") && (ticketsStatus == 3 || ticketsStatus == 4 || ticketsStatus == 5), PatrolResultEntity::getDevName)
                .orderByAsc((ticketsStatus == 3 || ticketsStatus == 4 || ticketsStatus == 5), PatrolResultEntity::getCheckTime)
        );
        List<PatrolResultVo> voList = BeanUtil.copyToList(data.getRecords(), PatrolResultVo.class);
        Page<PatrolResultVo> voPage = new Page<>();
        BeanUtil.copyProperties(data, voPage);
        voPage.setRecords(voList);
        return R.ok(voPage);
    }

    @GetMapping("/{id}")
    @Operation(summary = "查询单条巡检详情")
    public R<PatrolResultVo> getById(@PathVariable("id") Integer id) {
        PatrolResultEntity data = patrolResultService.getById(id);
        PatrolResultVo vo = BeanUtil.copyProperties(data, PatrolResultVo.class);
        return R.ok(vo);
    }


    public record AlarmDisableVo(boolean enable, int hours, String text) {
    }

    public record AlarmDisableDto(boolean enable, int hours) {
    }

    @GetMapping("/{id}/alarmDisable")
    @Operation(summary = "查询巡检项重复报警设置")
    public R<AlarmDisableVo> alarmDisable(@PathVariable("id") Integer id) {
        PatrolResultEntity patrolResultEntity = patrolResultService.getById(id);
        TicketsEntity tickets = ticketsService.getById(patrolResultEntity.getTicketsId());
        String key = "patrol:alarmDisable:hours" + tickets.getAllotRobotSn() + ":" + patrolResultEntity.getItemId();
        String key2 = "patrol:alarmDisable:tips" + tickets.getAllotRobotSn() + ":" + patrolResultEntity.getItemId();
        int hours = Optional.ofNullable((Integer) RedisUtils.get(key)).orElse(0);
        String tips = Optional.ofNullable((String) RedisUtils.get(key2)).orElse("");
        return R.ok(new AlarmDisableVo(hours > 0, hours, tips));
    }


    @PutMapping("/{id}/alarmDisable")
    @Operation(summary = "更改巡检项重复报警设置")
    public R<AlarmDisableVo> alarmDisable(@PathVariable("id") Integer id, @RequestBody AlarmDisableDto param) {
        PatrolResultEntity patrolResultEntity = patrolResultService.getById(id);
        TicketsEntity tickets = ticketsService.getById(patrolResultEntity.getTicketsId());
        String key = "patrol:alarmDisable:hours" + tickets.getAllotRobotSn() + ":" + patrolResultEntity.getItemId();
        String key2 = "patrol:alarmDisable:tips" + tickets.getAllotRobotSn() + ":" + patrolResultEntity.getItemId();
        String s = "";
        if (param.enable && param.hours > 0) {
            RedisUtils.set(key, param.hours, (long) param.hours * 60 * 60);
            s = DateUtil.offset(new Date(), DateField.HOUR, param.hours).toString("yyyy-MM-dd HH:mm:ss") + "前不再重复报警";
            RedisUtils.set(key2, s, (long) param.hours * 60 * 60);
        } else {
            RedisUtils.del(key);
            RedisUtils.del(key2);
        }
        return R.ok(new AlarmDisableVo(param.enable, param.hours, s));
    }


    @Operation(summary = "修改巡检结果", description = "修改巡检结果")
    @PutMapping
    public R updateById(@RequestBody PatrolResultEntity patrolResult) {
        PatrolResultEntity old = patrolResultService.getById(patrolResult.getId());
        //误报的情况 生成备注
        if (Objects.equals(patrolResult.getAuditStatus(), 2) && StrUtil.isBlank(patrolResult.getAuditRemark())) {
            patrolResult.setAuditRemark("误报:" + patrolResult.getCause() + ",不做处理\n内操:" + patrolResult.getAuditor() + "外操:" + patrolResult.getOperator());
        }
        //正报生成告警
        if (!Objects.equals(patrolResult.getAuditStatus(), old.getAuditStatus()) && Objects.equals(patrolResult.getAuditStatus(), 1)) {
            TicketsEntity tickets = ticketsService.getById(old.getTicketsId());
            RobotWarningRecordEntity warning = new RobotWarningRecordEntity();
            //warning.setId(null);
            warning.setType("2");
            warning.setServiceId(Optional.ofNullable(tickets).map(TicketsEntity::getAllotRobotSn).orElse(""));
            warning.setTitle(Optional.ofNullable(tickets).map(TicketsEntity::getAllotRobotName).orElse("") + ":检测告警");
            warning.setContent(old.getItemName() + ",值:" + old.getShowValue() + ",异常(标准:" + old.getNormalValue() + ")");
            warning.setTime(old.getCheckTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime());
            warning.setLevel(0);
            warning.setFlag("0");
            warning.setFiles(old.getVisionMediaUrl());
            warning.setPatrolResultId(old.getId());
//            warning.setRemark(null);
//            warning.setAuditor("");
//            warning.setOperator("");
//            warning.setCause("");
//            warning.setApproach("");

            robotWarningRecordService.save(warning);
        }
        return R.ok(patrolResultService.updateById(patrolResult));
    }


    @GetMapping("/summary/{ticketsId}/export")
    @Operation(summary = "导出巡检报告")
    public void export(@PathVariable("ticketsId") Integer ticketsId, HttpServletResponse response) throws IOException {
        //查询是否有生成文件（任务完成后自动生成，避免大任务的文件写入时间等待）
        String patrolExcelFilePath = ExcelUtil.getPatrolExcelFilePath(fileProperties.getLocal().getBasePath(), ticketsId);
        if (FileUtil.exist(patrolExcelFilePath)) {
            File file = new File(patrolExcelFilePath);
            if (!file.canWrite()) {
                ExcelUtil.response2Web(response, "文件正在写入，请稍后重试");
                return;
            }
            if (file.length() == 0) {
                ExcelUtil.response2Web(response, "文件正在生成，请稍后重试");
                return;
            }
            //给前端返回文件
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setCharacterEncoding("utf-8");
            // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
            String fileName = URLEncoder.encode("智能巡检机器人巡检报告", StandardCharsets.UTF_8).replaceAll("\\+", "%20");
            response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
            ServletOutputStream outputStream = response.getOutputStream();
            outputStream.write(FileUtil.readBytes(patrolExcelFilePath));
            outputStream.close();
        } else {
            //本地写文件
            //查询数据
            CompletableFuture.runAsync(() -> {
                QueryPatrolSummaryParams query = new QueryPatrolSummaryParams();
                query.setTicketsId(ticketsId);
                PatrolResultSummaryVo summary = patrolResultService.summary(query);
                TicketsEntity tickets = ticketsService.getById(ticketsId);
                List<PatrolResultEntity> data = patrolResultService.list(
                        Wrappers.<PatrolResultEntity>lambdaQuery()
                                .eq(PatrolResultEntity::getTicketsId, ticketsId)
                                .orderByAsc(!tickets.getAllotRobotSn().contains("HITRAIL"), PatrolResultEntity::getDevName)
                                .orderByAsc(PatrolResultEntity::getCheckTime)
                );
                List<PatrolResultExcelDto> list = new ArrayList<>();
                //属性替换
                for (int i = 0; i < data.size(); i++) {
                    PatrolResultEntity patrolResult = data.get(i);
                    PatrolResultExcelDto excelDto = BeanUtil.copyProperties(patrolResult, PatrolResultExcelDto.class);
                    excelDto.setIndex(i + 1);//序号
                    String url = StrUtil.isBlank(patrolResult.getVisionMediaUrl()) ? patrolResult.getMediaUrl() : patrolResult.getVisionMediaUrl();
                    if (StrUtil.isNotBlank(url)) {
                        //服务端的链接带了sys-file
                        url = url.replace("/sys-file/", "");
                    }
                    excelDto.setPath(fileProperties.getLocal().getBasePath() + File.separator + url);//文件采用相对路径，所以要加前缀
                    list.add(excelDto);
                }
                //动态表头
                List<List<String>> headTitles = ExcelUtil.head(summary);
                //写文件
                EasyExcel.write(patrolExcelFilePath, PatrolResultExcelDto.class)
                        // 这里放入动态头
                        .head(headTitles)
                        .sheet("Sheet1")
                        .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
//                        .registerWriteHandler(new MultiColumnMergeHandler(data.size(),Arrays.asList(1,2)))//合并
                        // 当然这里数据也可以用 List<List<String>> 去传入
                        .doWrite(list);
            }, customThreadPool);
            ExcelUtil.response2Web(response, "开始生成报表，请稍后重试");
        }
    }


    public static PatrolGraphResultVo mapToGraphResult(List<PatrolResultEntity> entities) {
        if (entities == null || entities.isEmpty()) {
            return null;
        }

        PatrolGraphResultVo resultVo = new PatrolGraphResultVo();

        // Assuming all entities in the list are for the same item
        // You might need to adjust this if items are different
        resultVo.setItemName(entities.get(0).getItemName()); // or another field for item name

        // Determine if it's an enum and set unit
        boolean isEnum = false;
        String unit = null;

        List<PatrolResultEntity> list =
                entities.stream().filter(x -> !StringUtils.isBlank(x.getVisionResult())).toList();

        // Check if showValue and convertValue are different
        if (!list.get(0).getShowValue().equals(list.get(0).getConvertValue())) {
            // If different, the extra part in showValue is the unit
            unit = extractUnit(list.get(0).getShowValue(), list.get(0).getConvertValue());
        } else {
            // If same, check for enum cases
            String value = list.get(0).getShowValue().toLowerCase();
            if (value.equals("开") || value.equals("关") ||
                    value.equals("停止") || value.equals("手动") ||
                    value.equals("正常") || value.equals("异常")) {
                isEnum = true;
            }
        }

        resultVo.setIsEnum(isEnum ? 1 : 0);
        resultVo.setUnit(unit);

        // If it's an enum, build the enum map
        if (isEnum && (list.get(0).getShowValue().equals("开") || list.get(0).getShowValue().equals("关"))) {
            Map<String, String> enumMap = new HashMap<>();
            // Add your enum mappings here based on business logic
            // For example:
            enumMap.put("1", "开");
            enumMap.put("0", "关");
            // Add other enum values as needed
            resultVo.setMap(enumMap);
        }
        if (isEnum && (list.get(0).getShowValue().equals("停止") || list.get(0).getShowValue().equals("手动"))) {
            Map<String, String> enumMap = new HashMap<>();
            // Add your enum mappings here based on business logic
            // For example:
            enumMap.put("1", "手动");
            enumMap.put("0", "停止");
            // Add other enum values as needed
            resultVo.setMap(enumMap);
        }
        if (isEnum && (list.get(0).getShowValue().equals("正常") || list.get(0).getShowValue().equals("异常"))) {
            Map<String, String> enumMap = new HashMap<>();
            // Add your enum mappings here based on business logic
            // For example:
            enumMap.put("1", "正常");
            enumMap.put("0", "异常");
            // Add other enum values as needed
            resultVo.setMap(enumMap);
        }
        // Populate x (time) and y (values) lists
        List<String> xValues = new ArrayList<>();
        List<String> yValues = new ArrayList<>();

        for (PatrolResultEntity entity : entities) {
            xValues.add(formatCheckTime(entity.getCheckTime()));
            yValues.add(isEnum ? entity.getVisionResult() : entity.getConvertValue());
        }

        resultVo.setX(xValues);
        resultVo.setY(yValues);

        return resultVo;
    }

    private static String extractUnit(String showValue, String convertValue) {
        // Simple implementation - assumes unit is the difference between strings
        // You might need a more sophisticated approach based on your actual data
        return showValue.replace(convertValue, "").trim();
    }

    private static String formatCheckTime(Date checkTime) {
        // Format the date as needed
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return sdf.format(checkTime);
    }


    /************************************************CVD巡检报告********************************************************************/

    @PostMapping("/cvd/summary/page")
    @Operation(summary = "CVD分页查询巡检总览")
    public R<Page<PatrolResultSummaryNewVo>> cvdSummaryPage(@RequestBody QueryPatrolSummaryNewParams query) {
        try {
            return R.ok(patrolResultService.cvdSummaryPage(query));
        } catch (Exception e) {
            log.error("CVD分页查询巡检总览异常:{}", e.getMessage(), e);
            return R.failed("CVD分页查询巡检总览");
        }
    }

    @PostMapping("/cvd/detail/page")
    @Operation(summary = "CVD分页查询巡检详情")
    public R<Page<PatrolResultNewVo>> cvdDetailPage(@RequestBody QueryPatrolDetailNewParams query) {
        try {
            return R.ok(patrolResultService.cvdDetailPage(query));
        } catch (Exception e) {
            log.error("CVD分页查询巡检详情异常:{}", e.getMessage(), e);
            return R.failed("CVD分页查询巡检详情异常");
        }
    }

    @GetMapping("/cvd/export1/{execNo}")
    @Operation(summary = "导出CVD工艺参数报告")
    public void export1(@PathVariable("execNo") String execNo, HttpServletResponse response) throws IOException {
        String cvdPatrolFilePath = ExcelUtil.getCvdExcelFilePath(fileProperties.getLocal().getBasePath(), "patrol", execNo);
        if (FileUtil.exist(cvdPatrolFilePath)) {
            File file = new File(cvdPatrolFilePath);
            if (!file.canWrite()) {
                ExcelUtil.response2Web(response, "文件正在写入，请稍后重试");
                return;
            }
            if (file.length() == 0) {
                ExcelUtil.response2Web(response, "文件正在生成，请稍后重试");
                return;
            }
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setCharacterEncoding("utf-8");
            String fileName = URLEncoder.encode("工艺参数报告", StandardCharsets.UTF_8).replaceAll("\\+", "%20");
            response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
            ServletOutputStream outputStream = response.getOutputStream();
            outputStream.write(FileUtil.readBytes(cvdPatrolFilePath));
            outputStream.close();
        } else {
            CompletableFuture.runAsync(() -> {
                List<PatrolResultEntity> list= patrolResultService.list(Wrappers.<PatrolResultEntity>lambdaQuery()
                        .eq(PatrolResultEntity::getStoveExecNo, execNo)
                        .orderByAsc(PatrolResultEntity::getId)
                );
                //表头
                List<List<String>> headList = patrolResultService.headForPatrol(execNo);
                //数据
                List<Object> dataList = patrolResultService.getCvdPatrolList(execNo);
                //写文件
                EasyExcel.write(cvdPatrolFilePath)
                        // 这里放入动态头
                        .head(headList)
                        .sheet("Sheet1")
                        .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
                        .doWrite(dataList);
            }, customThreadPool);
            ExcelUtil.response2Web(response, "开始生成报表，请稍后重试");
        }
    }

    @GetMapping("/cvd/export2/{execNo}")
    @Operation(summary = "导出CVD安全状态报告")
    public void export2(@PathVariable("execNo") String execNo, HttpServletResponse response) throws IOException {
        String cvdSaveFilePath = ExcelUtil.getCvdExcelFilePath(fileProperties.getLocal().getBasePath(), "safe", execNo);
        if (FileUtil.exist(cvdSaveFilePath)) {
            File file = new File(cvdSaveFilePath);
            if (!file.canWrite()) {
                ExcelUtil.response2Web(response, "文件正在写入，请稍后重试");
                return;
            }
            if (file.length() == 0) {
                ExcelUtil.response2Web(response, "文件正在生成，请稍后重试");
                return;
            }
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setCharacterEncoding("utf-8");
            String fileName = URLEncoder.encode("安全状态报告", StandardCharsets.UTF_8).replaceAll("\\+", "%20");
            response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
            ServletOutputStream outputStream = response.getOutputStream();
            outputStream.write(FileUtil.readBytes(cvdSaveFilePath));
            outputStream.close();
        } else {
            CompletableFuture.runAsync(() -> {
                List<CvdSafeExcelDto> list = patrolResultService.getCvdSafeEventList(execNo);
                for (int i = 0; i < list.size(); i++) {
                    CvdSafeExcelDto cvdSafeExcelDto = list.get(i);
                    cvdSafeExcelDto.setIndex(i + 1);
                }
                //动态表头
                List<List<String>> headTitles = ExcelUtil.headForSafe();
                //写文件
                EasyExcel.write(cvdSaveFilePath, CvdSafeExcelDto.class)
                        // 这里放入动态头
                        .head(headTitles)
                        .sheet("Sheet1")
                        .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
                        .doWrite(list);
            }, customThreadPool);
            ExcelUtil.response2Web(response, "开始生成报表，请稍后重试");
        }
    }

    @GetMapping("/cvd/excel/delete/{execNo}")
    @Operation(summary = "删除cvd巡检报告和安全状态报告")
    public R<Boolean> refreshExcel(@PathVariable("execNo") String execNo) {
        try {
            String cvdSaveFilePath = ExcelUtil.getCvdExcelFilePath(fileProperties.getLocal().getBasePath(), "safe", execNo);
            String cvdPatrolFilePath = ExcelUtil.getCvdExcelFilePath(fileProperties.getLocal().getBasePath(), "patrol", execNo);
            if (FileUtil.exist(cvdSaveFilePath)) {
                FileUtil.del(cvdSaveFilePath);
            }
            if (FileUtil.exist(cvdPatrolFilePath)) {
                FileUtil.del(cvdPatrolFilePath);
            }
        } catch (Exception e) {
            log.error("删除cvd巡检报告和安全状态报告异常:{}", e.getMessage(), e);
            return R.failed("删除cvd巡检报告和安全状态报告异常");
        }
        return R.ok(true);
    }

}
